{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "W12_Homework",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true,
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/CIS-522/course-content/blob/main/tutorials/W12_DeepRL/W12_Homework.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gwZGV1Gy-Nwk"
      },
      "source": [
        "# CIS-522 Week 12 Homework\n",
        "\n",
        "\n",
        "**Instructor:** Dinesh Jayaraman\n",
        "\n",
        "**Content Creator:** Byron Galbraith, Alessandra Rossi Martins\n",
        "\n",
        "---"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "id": "TuHHlNkq4_Bz"
      },
      "source": [
        "#@markdown What is your Pennkey and pod? (text, not numbers, e.g. bfranklin)\n",
        "my_pennkey = '' #@param {type:\"string\"}\n",
        "my_pod = 'Select' #@param ['Select', 'euclidean-wombat', 'sublime-newt', 'buoyant-unicorn', 'lackadaisical-manatee','indelible-stingray','superfluous-lyrebird','discreet-reindeer','quizzical-goldfish','astute-jellyfish','ubiquitous-cheetah','nonchalant-crocodile','fashionable-lemur','spiffy-eagle','electric-emu','quotidian-lion']\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uK_6NmnCa0le"
      },
      "source": [
        "---\n",
        "# Setup"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "P2vMwrdbw-_y"
      },
      "source": [
        "# imports\n",
        "from copy import deepcopy\n",
        "from typing import NamedTuple\n",
        "import time\n",
        "\n",
        "import gym\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import scipy.signal\n",
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.nn.functional as F\n",
        "from torch.optim import Adam"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "id": "rdy3OaC1kATe"
      },
      "source": [
        "#@title Helper Methods\n",
        "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
        "\n",
        "\n",
        "def soft_update_from_to(source, target, tau):\n",
        "  for target_param, param in zip(target.parameters(), source.parameters()):\n",
        "    target_param.data.copy_(\n",
        "      target_param.data * (1.0 - tau) + param.data * tau\n",
        "  )\n",
        "\n",
        "\n",
        "class Batch(NamedTuple):\n",
        "  state: torch.Tensor\n",
        "  action: torch.Tensor\n",
        "  reward: torch.Tensor\n",
        "  discount: torch.Tensor\n",
        "  next_state: torch.Tensor\n",
        "\n",
        "\n",
        "class ReplayBuffer:\n",
        "  def __init__(self, state_dim, action_dim, buffer_size):\n",
        "    self.ptr = 0\n",
        "    self.n_samples = 0\n",
        "    self.buffer_size = buffer_size\n",
        "    \n",
        "    self.state = np.zeros((buffer_size, state_dim), dtype=np.float32)        \n",
        "    self.action = np.zeros((buffer_size, action_dim), dtype=np.float32)\n",
        "    self.reward = np.zeros(buffer_size, dtype=np.float32)\n",
        "    self.discount = np.zeros(buffer_size, dtype=np.float32)\n",
        "    self.next_state = np.zeros((buffer_size, state_dim), dtype=np.float32)\n",
        "\n",
        "  def add(self, state, action, reward, discount, next_state):\n",
        "    self.state[self.ptr] = state\n",
        "    self.action[self.ptr] = action\n",
        "    self.reward[self.ptr] = reward\n",
        "    self.discount[self.ptr] = discount\n",
        "    self.next_state[self.ptr] = next_state\n",
        "\n",
        "    if self.n_samples < self.buffer_size:\n",
        "      self.n_samples += 1\n",
        "\n",
        "    self.ptr = (self.ptr + 1) % self.buffer_size\n",
        "\n",
        "  def sample(self, batch_size):\n",
        "    # Select batch_size number of sample indicies at random from the buffer\n",
        "    idx = np.random.choice(self.n_samples, batch_size)    \n",
        "    # Using the random indices, assign the corresponding state, action, reward,\n",
        "    # discount, and next state samples.\n",
        "    state = self.state[idx]\n",
        "    action = self.action[idx]\n",
        "    reward = self.reward[idx]\n",
        "    discount = self.discount[idx]\n",
        "    next_state = self.next_state[idx]\n",
        "      \n",
        "    return Batch(state=torch.as_tensor(state, dtype=torch.float32).to(device),\n",
        "                 action=torch.as_tensor(action, dtype=torch.float32).to(device),\n",
        "                 reward=torch.as_tensor(reward, dtype=torch.float32).to(device),\n",
        "                 discount=torch.as_tensor(discount, dtype=torch.float32).to(device),\n",
        "                 next_state=torch.as_tensor(next_state, dtype=torch.float32).to(device))\n",
        "\n",
        "\n",
        "def learn_env(env, agent, gamma, n_steps):\n",
        "  ep_reward = []\n",
        "  ep_steps = []\n",
        "  total_reward = 0\n",
        "  t = 0\n",
        "  tic = time.time()\n",
        "  state = env.reset()\n",
        "  for step in range(n_steps):\n",
        "    action = agent.act(state)\n",
        "    next_state, reward, done, _ = env.step(action)    \n",
        "    discount = gamma*(1-done)\n",
        "    \n",
        "    total_reward += reward  \n",
        "  \n",
        "    agent.train(state, action, reward, discount, next_state, step)\n",
        "\n",
        "    if done:\n",
        "      toc = time.time()      \n",
        "      print(f\"Episode: {len(ep_reward) + 1}, reward: {total_reward:0.2f}, time:{toc-tic:0.2f}\")\n",
        "      tic = toc\n",
        "\n",
        "      state = env.reset()      \n",
        "      ep_reward.append(total_reward)\n",
        "      total_reward = 0\n",
        "      ep_steps.append(t)\n",
        "      t = 0\n",
        "    else:\n",
        "      state = next_state\n",
        "      t += 1\n",
        "\n",
        "  return ep_reward"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "u2TnUAEN-X8K"
      },
      "source": [
        "---\n",
        "# Section 1: Deep Deterministic Policy Gradient (DDPG)\n",
        "\n",
        "To reiterate a key point from the last section in the tutorial notebook, [Deep Deterministic Policy Gradient](https://arxiv.org/abs/1509.02971) extends DQN to continuous actions by introducing an actor network. The goal of the actor network is to predict the action that maximizes the Q-value given the current state. This effectively amortizes the argmax search into training. Concretely, let $\\mu_{\\theta}$ be an actor network paramterized by $\\theta$. The actor's objective is to output an action that maximizes its Q-value:\n",
        "\n",
        "\\begin{align}\n",
        "\\max_{\\theta} E_{s \\sim D}\\left[Q_{\\phi}(s, \\mu_{\\theta}(s))\\right]\n",
        "\\end{align}\n",
        "\n",
        "and the Q network's loss becomes\n",
        "\n",
        "\\begin{align}\n",
        "L(\\phi, D) = E_{(s, a, r, s') \\sim D}\\left[\\left(Q_\\phi(s, a) - (r + \\gamma Q(s', \\mu_{\\theta}(s'))\\right)^2\\right]\n",
        "\\end{align}\n",
        "\n",
        "where we have replaced $\\max_{a'}Q(s', a')$ with $Q(s', \\mu_\\theta(s'))$. During training, we optimize the actor network and the Q network jointly using gradient descent.\n",
        "\n",
        "In this homework you are going to implement parts of DDPG and then run it on a classic continuous control task. In addition to the original paper referenced above, you are also encouraged to read the [OpenAI Spinning Up entry on DDPG](https://spinningup.openai.com/en/latest/algorithms/ddpg.html), as it provides a succinct overview of the algorithm itself and is what this implementation is based on.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "srz5n9LtkZty"
      },
      "source": [
        "## The Actor\n",
        "The Actor takes on the role of our policy. In our previous DQN models, this was epsilon greedy applied to the argmax of our q-values. With continuous action spaces we can't do that, so we now turn to a neural network to learn this policy by mapping states to actions. Here we use a multi-layer perceptron with two hidden layers of 256 neurons each with ReLU activations for the hidden layers and tanh for the final layer. This assumes an action space bounded in [-1,1]. In case we do differ from that, we keep track of the true max value and scale the result accordingly. The model components are setup for you, so you need to complete the forward method."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZsoB66IRcS5H"
      },
      "source": [
        "class Actor(nn.Module):\n",
        "  def __init__(self, state_dim, action_dim, action_limit):\n",
        "    super().__init__()    \n",
        "    self.fc1 = nn.Linear(state_dim, 256)\n",
        "    self.fc2 = nn.Linear(256, 256)\n",
        "    self.fc3 = nn.Linear(256, action_dim)    \n",
        "    self.action_limit = action_limit\n",
        "\n",
        "  def forward(self, state):\n",
        "    # Pass the state through the first layer and apply a ReLU activation\n",
        "    x = ...\n",
        "    # Next pass the result through the second layer and apply a ReLU activation\n",
        "    x = ...\n",
        "    # Now pass the result through the third layer and apply a tanh activation\n",
        "    x = ...\n",
        "    # Finally scale the result by the action limit and return\n",
        "    x = ...\n",
        "    return x"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6vGwjW5clm9J"
      },
      "source": [
        "## The Critic\n",
        "The Critic is another model whose job is to provide a score for how well our policy, i.e. the Actor, is doing. This is our q-value function approximator from our DQN examples with one key difference. In the discrete case we can have our Q network take in the state and produce an array of values for each possible action. In the continuous case this isn't possible, so instead we treat the action as another input which we concatenate to the state and then have the Q network predict the single value for this combined state-action representation.\n",
        "\n",
        "Like the Actor, we will use a multi-layer perceptron with two hidden layers of 256 neurons each with ReLU activations after the hidden layers. Since our output is an unbounded scalar representing our value, we don't apply any activation function to the last layer. Once again we have provided the model components and you need to complete the forward method."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "2jX8zSl1cwLq"
      },
      "source": [
        "class Critic(nn.Module):\n",
        "  def __init__(self, state_dim, action_dim):\n",
        "    super().__init__()\n",
        "    self.fc1 = nn.Linear(state_dim + action_dim, 256)\n",
        "    self.fc2 = nn.Linear(256, 256)\n",
        "    self.fc3 = nn.Linear(256, 1)\n",
        "\n",
        "  def forward(self, state, action):\n",
        "    # First concatenate the state and action together\n",
        "    x = ...\n",
        "    # Next pass the result through the first layer and apply a ReLU activation\n",
        "    x = ...\n",
        "    # Then pass the result through the second layer and apply a ReLU activation\n",
        "    x = ...\n",
        "    # Finally  pass the result through the third layer\n",
        "    x = ...\n",
        "    # Ensure result has the right dimensions and return\n",
        "    x = torch.squeeze(x, -1)\n",
        "    return x  "
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NpNg-j-QnLo0"
      },
      "source": [
        "Now we have an Actor and a Critic, we need to create our agent that will train these for a given environment. We will use the same tricks from the DQN models with regard to experience replay and target networks. Implementations to enable both of these are provided. We will also follow a similar pattern as in the tutorials where the DDPGAgent class will implement the act and train methods which are used to interact with the povided `learn_env` method. Given the added complexity needing to update two networks, we have broken those parts out into an `update` method which is where you will implement the actor and critic training steps.\n",
        "\n",
        "In addition to the other tricks already mentioned, DDPG adds a few more:\n",
        "1. Delayed training -- Instead of training on every timestep, we run for 50 steps then train on 50 batches. This allows us to accumulate a better diversity of samples to collect batches from early on. You can see this in the `train` method.\n",
        "2. Exploration -- Recall that in the discrete action case we used epsilon greedy which provided exploration in the form of randomly choosing actions with some small percentage. Since we can't do that here, we will instead add a small amount of noise to the continous action value. You can see this in the `act` method.\n",
        "\n",
        "For implementation, we are once again using the `Batch` convenience object for getting batches from our replay buffer. To get the batch of states, actions, etc. from the `batch` object use `batch.state`, `batch.action`, etc."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "lHKHjw9nm-O2"
      },
      "source": [
        "class DDPGAgent:\n",
        "  def __init__(self, actor, actor_optimizer, critic, critic_optimizer, tau,\n",
        "               replay_buffer, batch_size, train_start, update_every, action_space, epsilon):\n",
        "    self.actor = actor\n",
        "    # Copy the actor network to get the target and disable autograd for performance\n",
        "    self.actor_target = deepcopy(actor)\n",
        "    for p in self.actor_target.parameters():\n",
        "      p.requires_grad = False\n",
        "    self.actor_optimizer = actor_optimizer\n",
        "\n",
        "    self.critic = critic\n",
        "    # Copy the critic network to get the target and disable autograd for performance\n",
        "    self.critic_target = deepcopy(critic)\n",
        "    for p in self.critic_target.parameters():\n",
        "      p.requires_grad = False\n",
        "    self.critic_optimizer = critic_optimizer\n",
        "\n",
        "    self.tau = tau\n",
        "\n",
        "    self.replay_buffer = replay_buffer\n",
        "    self.batch_size = batch_size\n",
        "    self.train_start = train_start\n",
        "    self.update_every = update_every\n",
        "    self.epsilon = epsilon\n",
        "    self.action_space = action_space\n",
        "    self.is_waiting = True\n",
        "  \n",
        "  def act(self, state):\n",
        "    # Disable autograd for performance when choosing an action\n",
        "    with torch.no_grad():\n",
        "      # if we are in pre-training, sample randomly from the action space\n",
        "      if self.is_waiting:\n",
        "        return self.action_space.sample()\n",
        "  \n",
        "      # get an action from our policy i.e. actor network\n",
        "      action = self.actor(torch.as_tensor(state, dtype=torch.float32).to(device))\n",
        "      # apply standard normal noise to the action value to encourage exploration\n",
        "      action = action.cpu().numpy() + self.epsilon * np.random.standard_normal(action.shape)\n",
        "      return action\n",
        "        \n",
        "  def train(self, state, action, reward, discount, next_state, t):\n",
        "    self.replay_buffer.add(state, action, reward, discount, next_state)  \n",
        "    \n",
        "    if t < self.train_start:\n",
        "      return\n",
        "    \n",
        "    if t == self.train_start:\n",
        "      self.is_waiting = False\n",
        "\n",
        "    # batch update every several steps instead of once per step\n",
        "    if t % self.update_every == 0:\n",
        "      for _ in range(self.update_every):\n",
        "        batch = self.replay_buffer.sample(self.batch_size)\n",
        "        self.update(batch)\n",
        "  \n",
        "  def update(self, batch):\n",
        "    # First, let's train the Critic network\n",
        "    \n",
        "    # Compute the predicted q-value from the critic network with the state and\n",
        "    # action\n",
        "    q_pred = self.critic(batch.state, batch.action)\n",
        "    \n",
        "    # Now compute the q-value target (also called td target or bellman backup)\n",
        "    # we don't need to compute gradients on the q-value target, just the q-value\n",
        "    # prediction, so we disable autograd here to speed up performance\n",
        "    with torch.no_grad():\n",
        "      # First, we will use the actor_target network to predict the best action\n",
        "      # for the next state\n",
        "      actor_target_action = ...\n",
        "      # Next we will get the q-value target from our critic_target network,\n",
        "      # using the the next state and the action we just got\n",
        "      q_target = ...\n",
        "      # Next apply the reward and discount to get the q-value target\n",
        "      q_target = ...\n",
        "\n",
        "    # Compute the MSE loss between the predicted and target values\n",
        "    loss_critic = ...\n",
        "\n",
        "    # backpropogation to update the critic network\n",
        "    self.critic_optimizer.zero_grad()    \n",
        "    loss_critic.backward()\n",
        "    self.critic_optimizer.step()\n",
        "\n",
        "    # Next, let's train the Actor network\n",
        "\n",
        "    # We disable autograd for the critic network during this phase to increase\n",
        "    # performance\n",
        "    for p in self.critic.parameters():\n",
        "      p.requires_grad = False\n",
        "\n",
        "    # Get the predicted action for the state from the actor network\n",
        "    actor_action = ...\n",
        "    # Use this action along with the current state to see what q-value the\n",
        "    # critic network produces\n",
        "    q_actor = ...\n",
        "    # Since we want to maximize the value, our loss is just the negative of the\n",
        "    # mean of the batch of q-values we just got\n",
        "    loss_actor = ...\n",
        "\n",
        "    # backpropogation to update the critic network\n",
        "    self.actor_optimizer.zero_grad()    \n",
        "    loss_actor.backward()\n",
        "    self.actor_optimizer.step()\n",
        "\n",
        "    # Important! We need to unfreeze our critic network so it can be trained on\n",
        "    # the next step\n",
        "    for p in self.critic.parameters():\n",
        "      p.requires_grad = True\n",
        "\n",
        "    # Finally, soft update the target networks for both the actor and critic\n",
        "    with torch.no_grad():\n",
        "      soft_update_from_to(self.actor, self.actor_target, self.tau)\n",
        "      soft_update_from_to(self.critic, self.critic_target, self.tau)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oX2YJm5i7rTT"
      },
      "source": [
        "The environment we are going to test our agent out on is the OpenAI Gym version of the classic [pendulum control task](https://github.com/openai/gym/wiki/Pendulum-v0). An inverted pendulum starts in a random position and we must apply a real-valued force to get the pendulum to remain upright. The task ends after 200 steps with the reward at each step based on the current position, change in position, and force applied. This works out well as a test case for DDPG as there are only three elements in the state space and just a single element in the action space which makes this relatively fast to run and also achieve good results.\n",
        "\n",
        "The code below sets up everything we need to run our agent."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "IFs-qFNzxQws"
      },
      "source": [
        "# hyperparameters\n",
        "seed = 522\n",
        "buffer_size = 10000\n",
        "gamma = 0.99\n",
        "tau = 0.005\n",
        "epsilon = 0.1\n",
        "batch_size = 100\n",
        "train_start = 1000\n",
        "update_every = 50\n",
        "n_steps = 10000\n",
        "\n",
        "# environment setup\n",
        "torch.manual_seed(seed)\n",
        "np.random.seed(seed)\n",
        "\n",
        "env = gym.make('Pendulum-v0')\n",
        "state_dim = env.observation_space.shape[0]\n",
        "action_dim = env.action_space.shape[0]\n",
        "action_limit = env.action_space.high[0]\n",
        "\n",
        "# Create actor-critic modules and optimizers\n",
        "actor = Actor(state_dim, action_dim, action_limit).to(device)\n",
        "critic = Critic(state_dim, action_dim).to(device)\n",
        "actor_optimizer = Adam(actor.parameters(), lr=1e-3)\n",
        "critic_optimizer = Adam(critic.parameters(), lr=1e-3)\n",
        "\n",
        "# Initialize our experience replay buffer\n",
        "replay_buffer = ReplayBuffer(state_dim, action_dim, buffer_size)\n",
        "\n",
        "# Create out agent\n",
        "agent = DDPGAgent(actor, actor_optimizer, critic, critic_optimizer, tau, \n",
        "                  replay_buffer, batch_size, train_start, update_every,\n",
        "                  env.action_space, epsilon)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BhoN-R9s7VSL"
      },
      "source": [
        "If everything is correct, you should see the agent starting to improve in a short amount of time with dramatic improvement by the end of the 50 episodes that corresponds to 10000 steps."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "JqREofNUyVbv"
      },
      "source": [
        "ep_rewards = learn_env(env, agent, gamma, n_steps)\n",
        "plt.plot(ep_rewards)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Kv3uEAHU-c6G"
      },
      "source": [
        "---\n",
        "# Section 2: Ethics\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pObDk6033JJV"
      },
      "source": [
        "## Part I: Relevance and efficiency of standards: local vs. global\n",
        "\n",
        "By looking back at the discussions of the semester, it is possible to safely infer that the adoption and deployment of AI tools have ethical and societal implications. The adoption of standards is one approach that has been largely discussed in the U.S. and globally to deal with these implications and give AI developers and users some guidelines. \n",
        "\n",
        "To have an overview of which standards are being largely considered and their role, we will read [A Plan for Federal Engagement in Developing Technical Standards and Related Tools](https://www.nist.gov/system/files/documents/2019/08/10/ai_standards_fedengagement_plan_9aug2019.pdf) published by the National Institute of Standards and Technology from the Department of Commerce. \n",
        "\n",
        "Read the first excerpt (pages 7-16; PDF pages 9-18) which explains the US approach to standards.  Select one standard that you consider is the most relevant to an application covered in the semester. Offer your analysis of why this standard is important to guarantee the feasibility of this application.\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "id": "89Iibqfl4kOt"
      },
      "source": [
        "important_standard = \"\" #@param {type:\"string\"}\n",
        "\n",
        "try:t1;\n",
        "except NameError: t1 = time.time()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3g2Jhgrz3t_3"
      },
      "source": [
        "Next, we will read excerpts from [The Chinese Approach to Artificial Intelligence: An Analysis of Policy, Ethics, and Regulation](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3469784) published in the AI & Society Journal of Knowledge, Culture and Communication and [Artificial Intelligence: A European approach to excellence and trust](https://ec.europa.eu/info/sites/info/files/commission-white-paper-artificial-intelligence-feb2020_en.pdf) published by the European Commission. \n",
        "\n",
        "These readings will bring some light into the discussions held in other parts of the world where AI adoption is largely discussed: the European Union and China. AI – such as most technologies – are hard to be considered in a jurisdictional cluster and different standards in different jurisdictions may cause relevant impacts in the development and adoption of a tool. \n",
        "\n",
        "Read Chapters 1 (pages 1-3; PDF pages 2-4) and 5 (pages 9-25; PDF pages 10-26) of [Artificial Intelligence: A European approach to excellence and trust](https://ec.europa.eu/info/sites/info/files/commission-white-paper-artificial-intelligence-feb2020_en.pdf) and then Section 4 (pages 19-28; PDF pages 19-28) of [The Chinese Approach to Artificial Intelligence: An Analysis of Policy, Ethics, and Regulation](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3469784).  Compare the EU and Chinese approaches to the standard analyzed above."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "id": "jpnHWnVb4jp_"
      },
      "source": [
        "eu_chinese_comparison = \"\" #@param {type:\"string\"}\n",
        "\n",
        "try:t2;\n",
        "except NameError: t2 = time.time()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nKiiUNfg4DKA"
      },
      "source": [
        "Next, consider a specific application of deep learning.  (For example, select autonomous vehicles, medical diagnostic systems, facial recognition systems, or a similar autonomous system or application.)\n",
        "\n",
        "Then, consider if there any differences between the US, EU and Chinese approaches. Which approach do you find is best suited to foster the development of the specific application you selected?  What are the implications of these different approaches (if any) to the development of the application you selected?  Would a global standardized approach be beneficial?  In what ways?"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "id": "mDOWSi1U4lQh"
      },
      "source": [
        "better_approach = \"\" #@param {type:\"string\"}\n",
        "global_standard = \"\" #@param {type:\"string\"}\n",
        "\n",
        "try:t3;\n",
        "except NameError: t3 = time.time()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "T6RQEUbd3SgT"
      },
      "source": [
        "## Part II: Ethics and standards in the cost-benefit analysis of AI adoption in the private and public sectors\n",
        "\n",
        "Next, consider the effects of the ethical dilemmas and the role the standards you studied in Part I above play in the decisions private companies and public officials need to make on whether or not to adopt an AI tool.\n",
        "\n",
        "Do you think that the standards bring more security, transparency or trust into the decision-making process? Why? If you were in charge of deciding whether or not to develop and adopt the AI application you selected in Part I above in a private company, would you rather rely on standards or not? What if you were a public official making the decision to adopt such an application in a government agency? \n",
        "\n",
        "Moreover, reflect on the cost-benefit analysis entities – both private and public - need to make and how the standards play a role in these decisions. Do standards give decision makers more room to make an informed decision or not?\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5JfIVTUk3R1s",
        "cellView": "form"
      },
      "source": [
        "part_II_response = \"\" #@param {type:\"string\"}\n",
        "\n",
        "try:t4;\n",
        "except NameError: t4 = time.time()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "p3MgbUSL6PNj"
      },
      "source": [
        "---\n",
        "# Submission\n",
        "\n",
        "Once you're done, click on 'Share' and add the link to the box below. If you did not use CoLab, you can also upload the file or notebook in the form below."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "id": "EcjaJHlI6TRu"
      },
      "source": [
        "link = '' #@param {type:\"string\"}"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "aDIHyhUV6ZLT",
        "cellView": "form"
      },
      "source": [
        "import time\n",
        "import numpy as np\n",
        "import urllib.parse\n",
        "from IPython.display import IFrame\n",
        "\n",
        "\n",
        "#@markdown #Run Cell to Show Airtable Form\n",
        "#@markdown ##**Confirm your answers and then click \"Submit\"**\n",
        "\n",
        "\n",
        "def prefill_form(src, fields: dict):\n",
        "  '''\n",
        "  src: the original src url to embed the form\n",
        "  fields: a dictionary of field:value pairs,\n",
        "  e.g. {\"pennkey\": my_pennkey, \"location\": my_location}\n",
        "  '''\n",
        "  prefill_fields = {}\n",
        "  for key in fields:\n",
        "      new_key = 'prefill_' + key\n",
        "      prefill_fields[new_key] = fields[key]\n",
        "  prefills = urllib.parse.urlencode(prefill_fields)\n",
        "  src = src + prefills\n",
        "  return src\n",
        "\n",
        "\n",
        "#autofill fields if they are not present\n",
        "#a missing pennkey and pod will result in an Airtable warning\n",
        "#which is easily fixed user-side.\n",
        "try: my_pennkey;\n",
        "except NameError: my_pennkey = \"\"\n",
        "try: my_pod;\n",
        "except NameError: my_pod = \"Select\"\n",
        "try: important_standard;\n",
        "except NameError: important_standard = \"\"\n",
        "try: eu_chinese_comparison\n",
        "except NameError: eu_chinese_comparison = \"\"\n",
        "try: better_approach\n",
        "except NameError: better_approach = \"\"\n",
        "try: global_standard\n",
        "except NameError: global_standard = \"\"\n",
        "try: part_II_response;\n",
        "except NameError: part_II_response = \"\"\n",
        "try: link;\n",
        "except NameError: link = \"\"\n",
        "\n",
        "fields = {\"pennkey\": my_pennkey,\n",
        "          \"pod\": my_pod,\n",
        "          \"important_standard\": important_standard,\n",
        "          \"eu_chinese_comparison\": eu_chinese_comparison,\n",
        "          \"better_approach\": better_approach,\n",
        "          \"global_standard\": global_standard,\n",
        "          \"part_II_response\": part_II_response,\n",
        "          \"link\": link}\n",
        "\n",
        "src = \"https://airtable.com/embed/shrKHlqxJWnwxMoCp?\"\n",
        "\n",
        "\n",
        "#now instead of the original source url, we do: src = prefill_form(src, fields)\n",
        "display(IFrame(src = prefill_form(src, fields), width = 800, height = 400))"
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}